package cn.com.nes.site.service.crm.order.impl;

import cn.com.nes.common.exception.IllegalBusinessException;
import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.CopyUtils;
import cn.com.nes.common.util.XzqhUtils;
import cn.com.nes.mybatis.agent.crm.entity.Customer;
import cn.com.nes.mybatis.agent.crm.entity.Opportunity;
import cn.com.nes.mybatis.agent.ope.entity.SaleOrderInfo;
import cn.com.nes.mybatis.agent.ope.entity.SalePriceMaster;
import cn.com.nes.mybatis.agent.ope.mapper.SaleOrderInfoMapper;
import cn.com.nes.mybatis.agent.system.entity.TUser;
import cn.com.nes.site.entity.PageData;
import cn.com.nes.site.entity.bo.crm.sale.*;
import cn.com.nes.site.entity.em.DeleteEnum;
import cn.com.nes.site.entity.em.crm.saleorder.SaleOrderDistributeStatusEnum;
import cn.com.nes.site.entity.em.crm.saleorder.SaleOrderStatusEnum;
import cn.com.nes.site.entity.em.crm.saleorder.SignSaleOrderStatusEnum;
import cn.com.nes.site.entity.vo.crm.QueryCustomerPageVo;
import cn.com.nes.site.entity.vo.crm.SalePriceMasterVO;
import cn.com.nes.site.entity.vo.crm.sale.*;
import cn.com.nes.site.service.crm.customer.CrmCustomerService;
import cn.com.nes.site.service.crm.customer.dto.CustomerDTO;
import cn.com.nes.site.service.crm.opportunity.CrmOpportunityService;
import cn.com.nes.site.service.crm.order.SaleOrderInfoService;
import cn.com.nes.site.service.crm.order.SalePriceDetailService;
import cn.com.nes.site.service.crm.order.SalePriceService;
import cn.com.nes.site.service.crm.order.bo.*;
import cn.com.nes.site.service.crm.order.dto.SaleOrderDetailDTO;
import cn.com.nes.site.service.crm.order.dto.SaleOrderInfoDTO;
import cn.com.nes.site.service.crm.order.dto.SalePriceDetailDTO;
import cn.com.nes.site.service.crm.order.dto.SalePriceMasterDTO;
import cn.com.nes.site.service.system.dict.TParamService;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.com.nes.site.service.system.user.SystemUserService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 销售订单实现
 */
@Slf4j
@Service
public class SaleOrderInfoServiceImpl extends ServiceImpl<SaleOrderInfoMapper, SaleOrderInfo> implements SaleOrderInfoService {

    @Resource
    private SalePriceService salePriceService;

    @Resource
    private SystemUserService systemUserService;

    @Resource
    private TParamService tParamService;

    @Resource
    private CrmCustomerService crmCustomerService;

    @Resource
    private XzqhService xzqhService;

    @Resource
    private CrmOpportunityService crmOpportunityService;

    @Resource
    private SalePriceDetailService salePriceDetailService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData saveOrder(SaleOrderInfoVO vo) throws Exception {
        boolean addNew = ObjectUtil.isNull(vo.getId());

        // 给订单设置必要属性
        SaleOrderInfo orderInfo = new SaleOrderInfo();
        BeanUtils.copyProperties(vo, orderInfo);
        orderInfo.setAreaCode(vo.getXzqhdm());
        orderInfo.setInstallInfoId(vo.getHouseId());
        // 新增销售订单
        if (addNew) {
            // 设置相同商机下，其他订单为不启用状态，且订单状态为废单。
            disableSaleOrderForOpportunity(vo.getBusinessId());

            // 初始化订单状态
            initSaleOrder(orderInfo, vo.getOperateUserId(), vo.getOperateDate(), vo.getOperateUserCompanyId());
        } else {
            orderInfo.setCommit(null);
        }

        orderInfo.setGmtModified(vo.getOperateDate());
        orderInfo.setGmtModifiedId(vo.getOperateUserId());

        log.info("订单详情:" + JSON.toJSONString(orderInfo));
        this.saveOrUpdate(orderInfo);
        // 给报价单加标识
        Long orderId = orderInfo.getId();
        //        if (CollectionUtil.isNotEmpty(vo.getPriceSheetIdList())) {
        //            salePriceService.signPriceSheet(vo.getPriceSheetIdList(), orderId, vo.getOperateUserId(), vo.getCommit());
        //        }
        // 返回订单id
        return PageData.ok("id", orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaleOrderInfoDTO saleOrderSave(SaleOrderBO saleOrderBO) throws Exception {
        // 保存订单主表
        SaleOrderInfo saleOrderInfo = buildSaleOrder(saleOrderBO);
        this.saveOrUpdate(saleOrderInfo);
        saleOrderBO.setSaleOrderId(saleOrderInfo.getId());

        saveForMastersAndDetails(saleOrderBO);


        SaleOrderInfoDTO saleOrderInfoDTO = new SaleOrderInfoDTO();
        BeanUtils.copyProperties(saleOrderInfo, saleOrderInfoDTO);
        return saleOrderInfoDTO;
    }

    /**
     * Saves sale masters and details for a given sale order.
     * It iterates over the sale masters associated with the provided sale order,
     * sets necessary fields, and persists each master order using the salePriceService.
     *
     * @param saleOrderBO The business object containing sale order details including masters and other entities.
     */
    private void saveForMastersAndDetails(SaleOrderBO saleOrderBO) throws Exception {
        if (CollUtil.isEmpty(saleOrderBO.getSaleMasters())) {
            return;
        }

        if (saleOrderBO.isHandleForExcelImport()) {
            SaleMasterBO saleMasterBO = saleOrderBO.getSaleMasters().get(0);
            SalePriceMaster salePriceMaster = salePriceService.getPriceMaster(saleOrderBO.getSaleOrderId(), saleMasterBO.getSaleMasterName());
            if (ObjectUtil.isNotNull(salePriceMaster)) {
                saleMasterBO.setMasterId(salePriceMaster.getId());
                saleMasterBO.setAddMaster(Boolean.FALSE);
            } else {
                saleMasterBO.setAddMaster(Boolean.TRUE);
            }
            BeanUtils.copyProperties(saleMasterBO, saleOrderBO);
            saleMasterBO.setCustomerUuid(saleOrderBO.getCustomerUuid());
            saleMasterBO.setBuildId(saleOrderBO.getHouseId());
            saleMasterBO.setCompanyId(saleOrderBO.getCompanyId());
            saleMasterBO.setOrderId(saleOrderBO.getSaleOrderId());
            salePriceService.saveMasterOrder(saleMasterBO);

            return;
        }

        for (SaleMasterBO saleMaster : saleOrderBO.getSaleMasters()) {
            saleMaster.setAddMaster(ObjectUtil.isNull(saleMaster.getMasterId()));
            BeanUtils.copyProperties(saleOrderBO, saleMaster);
            saleMaster.setCustomerUuid(saleOrderBO.getCustomerUuid());
            saleMaster.setBuildId(saleOrderBO.getHouseId());
            saleMaster.setCompanyId(saleOrderBO.getCompanyId());
            saleMaster.setOrderId(saleOrderBO.getSaleOrderId());

            try {
                salePriceService.saveMasterOrder(saleMaster);
            } catch (Exception e) {
                log.error("", e);
                throw new RuntimeException(e);
            }
        }
    }

    private @NotNull SaleOrderInfo
    buildSaleOrder(SaleOrderBO bo) {
        SaleOrderInfo saleOrderInfo = getSaleOrder(bo.getSaleOrderId());
        saleOrderInfo.setId(ObjectUtil.isNull(bo.getSaleOrderId()) ? null : bo.getSaleOrderId());
        if (bo.isAddOrder()) {
            saleOrderInfo.setGmtCreateId(bo.getOperateUserId());
            saleOrderInfo.setGmtCreate(bo.getOperateDate());
            saleOrderInfo.setDeleted(Boolean.parseBoolean(String.valueOf(DeleteEnum._0.getKey())));
        }
        BeanUtils.copyProperties(bo, saleOrderInfo);
        saleOrderInfo.setBusinessId(bo.getOpportunityUuid());
        saleOrderInfo.setCustomerId(bo.getCustomerUuid());
        saleOrderInfo.setCompanyId(bo.getCompanyId());
        saleOrderInfo.setSaleOrderName(bo.getSaleOrderName());
        saleOrderInfo.setAreaCode(bo.getAreaCode());
        saleOrderInfo.setPhone(bo.getPhone());
        saleOrderInfo.setInstallInfoId(bo.getHouseId());
        saleOrderInfo.setInstallAddress(bo.getInstallAddress());
        saleOrderInfo.setStatus(bo.getSaleOrderStatus().getKey());
        saleOrderInfo.setOrderType(bo.getOrderType().getKey());
        saleOrderInfo.setCommit(bo.getCommit());
        saleOrderInfo.setPayModel(bo.getPayModel().getKey());
        saleOrderInfo.setGmtModifiedId(bo.getOperateUserId());
        saleOrderInfo.setGmtModified(bo.getOperateDate());
        saleOrderInfo.setDistributeStatus(null);
        saleOrderInfo.setRealTradingTime(bo.getRealTradingTime());
        saleOrderInfo.setEstimatedInstallTime(bo.getEstimatedInstallTime());
        saleOrderInfo.setOtherCostPrice(bo.getOtherCostPrice());
        return saleOrderInfo;
    }


    private SaleOrderInfo getSaleOrder(Long orderId) {
        if (ObjectUtil.isNull(orderId)) {
            return new SaleOrderInfo();
        }
        SaleOrderInfo saleOrderInfo = this.getById(orderId);
        return ObjectUtil.isNull(saleOrderInfo) ? new SaleOrderInfo() : saleOrderInfo;
    }


    private static void initSaleOrder(SaleOrderInfo orderInfo, Long operateUserId, Date operateDate, String companyId) {
        enableSaleOrde(orderInfo);
        orderInfo.setDeleted(Boolean.FALSE);
        orderInfo.setGmtCreate(operateDate);
        orderInfo.setGmtCreateId(operateUserId);
        orderInfo.setGmtModified(operateDate);
        orderInfo.setGmtModifiedId(operateUserId);
        orderInfo.setCompanyId(companyId);
    }

    @Override
    public Page<SaleOrderInfoDTO> getOrderPage(SaleOrderPageVO vo) throws Exception {
        Page<SaleOrderInfo> page = new Page<>(vo.getPageid(), vo.getPagesize()); // 准备分页参数
        Page<SaleOrderInfoDTO> page2 = new Page<>(vo.getPageid(), vo.getPagesize()); // 准备分页参数
        List<SaleOrderInfoDTO> orderList = new ArrayList<>();   // 准备返回值列表
        // 组装查询参数
        QueryWrapper<SaleOrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", false);
        wrapper.eq("company_id", vo.getOperateUserCompanyId());
        if (StrUtil.isNotBlank(vo.getSaleOrderName())) {
            wrapper.like("sale_order_name", vo.getSaleOrderName()); // 订单名称
        }
        if (ObjectUtil.isNotNull(vo.getCommit())) {
            wrapper.eq("commit", vo.getCommit());   // 订单成交状态
        }
        if (ObjectUtil.isNotNull(vo.getStatus())) {
            wrapper.eq("status", vo.getStatus());   // 订单支付状态
        }
        if (StrUtil.isNotBlank(vo.getPhone())) {
            wrapper.eq("phone", vo.getPhone());   // 联系电话
        }
        if (StrUtil.isNotBlank(vo.getBusinessId())) {
            wrapper.eq("business_id", vo.getBusinessId());   // 商机ID
        }
        if (StrUtil.isNotBlank(vo.getCustomerId())) {
            wrapper.eq("customer_id", vo.getCustomerId());   // 客户ID
        }
        if (StrUtil.isNotBlank(vo.getXzqhdm())) {
            wrapper.likeRight("area_code", XzqhUtils.getRegionCodePrefix(vo.getXzqhdm())); // 行政区划代码
        }
        // 客户姓名
        if (StrUtil.isNotBlank(vo.getCustomerName())) {
            // 按客户姓名模糊查询客户id
            List<String> customerIdList = crmCustomerService.getCustomerIdListByCustomerName(vo.getCustomerName());
            // 如果查询得客户姓名不存在，直接返回空
            if (CollectionUtil.isEmpty(customerIdList)) {
                return page2;
            }
            wrapper.in("customer_id", customerIdList); // 客户id列表
        }
        wrapper.orderByDesc("gmt_modified", "business_id"); // 按修改时间、id倒序查询

        // 查询销售订单分页
        Page<SaleOrderInfo> saleOrderInfoPage = (Page<SaleOrderInfo>) this.page(page, wrapper);
        // 转换分页类型 - 使用本项目统一分页
        orderList = CopyUtils.copyList(saleOrderInfoPage.getRecords(), SaleOrderInfoDTO.class);
        // 设置返回字段
        setField(orderList);
        // 设置子系统个数
        orderList.forEach(item -> {
            // 查询子系统个数
            List<Long> priceSheetIdList = salePriceService.getPriceSheetIdListByOrderId(item.getId());
            int count = 0;
            if (CollectionUtil.isNotEmpty(priceSheetIdList)) {
                count = priceSheetIdList.size();
            }
            item.setChildCount(count);

            if (StrUtil.isNotEmpty(item.getBusinessId())) {
                Opportunity opportunity = crmOpportunityService.getById(item.getBusinessId());
                if (ObjectUtil.isNotNull(opportunity)) {
                    item.setBusinessName(opportunity.getOpportunityName());
                    item.setOpportunitystage(opportunity.getOpportunityStage());
                }
            }

            CustomerDTO customerDTO = crmCustomerService.getCustomerById(item.getCustomerId());
            item.setCustomerNature(customerDTO.getCustomerNature());

            // 判断商机下是否存在销售单
            Boolean orderStatusOnSale = this.baseMapper.hasOrderStatusOnSale(item.getBusinessId());
            item.setEditState(orderStatusOnSale);
        });
        // 返回
        page2.setTotal(saleOrderInfoPage.getTotal());
        page2.setRecords(orderList);
        return page2;
    }

    @Override
    public PageData getOrderDetail(GetSaleOrderDeatilsVO vo) throws Exception {
        // 查详情
        SaleOrderInfo saleOrderInfo = this.getById(vo.getId());
        SaleOrderInfoDTO dto = new SaleOrderInfoDTO();
        BeanUtils.copyProperties(saleOrderInfo, dto);
        dto.setXzqhdm(saleOrderInfo.getAreaCode());
        // 给销售订单主体信息设置经纬度
        Map<String, BigDecimal> coordinate = xzqhService.getCoordinate(dto.getAreaCode());
        dto.setLongitude(coordinate.get("longitude"));
        dto.setLatitude(coordinate.get("latitude"));

        Opportunity opportunity = crmOpportunityService.getOpportunityDetailByUuid(saleOrderInfo.getBusinessId());
        dto.setBusinessName(opportunity.getOpportunityName());

        CustomerDTO customerDTO = crmCustomerService.getCustomerById(opportunity.getCustomerId());
        dto.setCustomerNature(customerDTO.getCustomerNature());

        // 查询该商机下是否存在销售单
        Boolean orderStatusOnSale = this.baseMapper.hasOrderStatusOnSale(saleOrderInfo.getBusinessId());
        dto.setEditState(orderStatusOnSale);

        log.info("销售订单主体: {}", dto);
        // 查询子列表
        List<SalePriceMasterDTO> detailList = new ArrayList<>();
        List<Long> priceSheetIds = salePriceService.getPriceSheetIdListByOrderId(dto.getId());
        if (CollectionUtil.isNotEmpty(priceSheetIds)) {
            for (Long priceSheetId : priceSheetIds) {
                SalePriceMasterVO priceSheetVO = new SalePriceMasterVO();
                priceSheetVO.setId(priceSheetId);
                priceSheetVO.setCustomerId(saleOrderInfo.getCustomerId());
                PageData pageData = salePriceService.getPriceSheetDetail(priceSheetVO);
                SalePriceMasterDTO salePriceDetail = JSON.parseObject(JSON.toJSONString(pageData.getPage()
                        .get(0)), SalePriceMasterDTO.class);
                detailList.add(salePriceDetail);
            }
        }
        log.info("销售订单下的系统报价单: {}", detailList);
        dto.setPriceSheetList(detailList);
        Page<SaleOrderInfoDTO> page = new Page<>(1, 1);
        List<SaleOrderInfoDTO> list = new ArrayList<>();
        list.add(dto);
        // 设置字段
        setField(list);
        return PageData.ok(page, list);
    }

    @Override
    public SaleOrderInfoDTO getOrderDetatil(Long saleOrderId) throws Exception {
        SaleOrderInfo saleOrderInfo = this.baseMapper.selectById(saleOrderId);
        if (ObjectUtil.isNull(saleOrderInfo)) {
            return null;
        }
        SaleOrderInfoDTO saleOrderInfoDTO = new SaleOrderInfoDTO();
        BeanUtils.copyProperties(saleOrderInfo, saleOrderInfoDTO);
        saleOrderInfoDTO.setInstallInfoId(saleOrderInfo.getInstallInfoId());


        QueryWrapper<SalePriceMaster> query = new QueryWrapper<>();
        query.eq("order_id", saleOrderId);
        List<SalePriceMaster> salePriceMasters = salePriceService.list(query);
        List<SalePriceMasterDTO> salePriceMasterDTOS = CopyUtils.copyList(salePriceMasters, SalePriceMasterDTO.class);
        saleOrderInfoDTO.setPriceSheetList(salePriceMasterDTOS);
        return saleOrderInfoDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData delOrderByOrderId(DeleteSaleOrderVO vo) throws Exception {

        SaleOrderInfo saleOrderInfo = this.getById(vo.getId());
        if (SignSaleOrderStatusEnum._DISTRIBUTION.getKey() == saleOrderInfo.getDistributeStatus()) {
            return PageData.error("当前销售订单已派发工单,不可删除");
        }

        SaleOrderInfo orderInfo = new SaleOrderInfo();
        orderInfo.setId(vo.getId());
        orderInfo.setDeleted(Boolean.TRUE);
        orderInfo.setGmtModified(vo.getOperateDate());
        orderInfo.setGmtModifiedId(vo.getOperateUserId());
        Integer rows = this.baseMapper.updateById(orderInfo); // 逻辑删除
        if (rows != 0) {
            return PageData.error("删除销售订单失败");
        }
        return PageData.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData enableSaleOrder(EnableSaleOrderBO bo) throws Exception {
        SaleOrderInfo orderInfo = getSaleOrderById(bo.getId());

        // 设置相同商机下，其他订单为不启用状态，且订单状态为废单。
        disableSaleOrderForOpportunity(orderInfo.getBusinessId());

        enableSaleOrde(orderInfo);
        orderInfo.setGmtModified(bo.getOperateDate());
        orderInfo.setGmtModifiedId(bo.getOperateUserId());
        this.baseMapper.updateById(orderInfo);

        // // 给报价单加标识
        // Long orderId = orderInfo.getId();
        // List<Long> priceSheetIdList = salePriceService.getPriceSheetIdListByOrderId(orderId);
        // salePriceService.signPriceSheet(priceSheetIdList, orderId, vo.getOperateUserId(), orderInfo.getCommit());

        return PageData.ok();
    }

    @Override
    public SaleOrderInfo getSaleOrderById(Long orderId) throws Exception {
        SaleOrderInfo saleOrder = this.baseMapper.selectById(orderId);
        if (ObjectUtil.isNull(saleOrder) || saleOrder.isDeleted()) {
            throw new IllegalBusinessException("订单不存在！");
        }
        return saleOrder;
    }

    @Override
    public List<SaleOrderInfo> getSaleOrderByCustomer(Long customerId) throws Exception {
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(new QueryWrapper<SaleOrderInfo>().eq("deleted", Boolean.FALSE)
                .eq("customer_id", customerId));
        return CollUtil.isEmpty(saleOrderInfos) ? Collections.emptyList() : saleOrderInfos;
    }

    @Override
    public List<SaleOrderInfo> getSale(String customerId, String opportunityId) {
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(new QueryWrapper<SaleOrderInfo>().eq("deleted", Boolean.FALSE)
                .eq("customer_id", customerId)
                .eq("business_id", opportunityId));
        return CollUtil.isEmpty(saleOrderInfos) ? Collections.emptyList() : saleOrderInfos;
    }

    @Override
    public List<SaleOrderInfo> getOrders(String opportunityUuid) throws Exception {
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(new QueryWrapper<SaleOrderInfo>().eq("deleted", Boolean.FALSE)
                .eq("business_id", opportunityUuid));
        return CollUtil.isEmpty(saleOrderInfos) ? Collections.emptyList() : saleOrderInfos;
    }

    @Override
    public SaleOrderInfo getSaleOrderNew(String opportunityUuid) throws Exception {
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(new QueryWrapper<SaleOrderInfo>().eq("deleted", Boolean.FALSE)
                .eq("commit", Boolean.TRUE)
                .eq("status", SaleOrderStatusEnum.PAID_SUCCESS.getKey())
                .eq("business_id", opportunityUuid));
        return CollUtil.isEmpty(saleOrderInfos) ? null : saleOrderInfos.get(0);
    }

    /**
     * 根据商机UUID列表获取销售订单信息。
     * @param opportunityUuids 商机UUID列表
     * @return 包含销售订单信息的列表
     * @throws Exception 如果获取销售订单信息时发生异常
     */
    @Override
    public List<SaleOrderInfo> getSaleOrders(List<String> opportunityUuids) throws Exception {
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(new QueryWrapper<SaleOrderInfo>().eq("deleted", Boolean.FALSE)
                .eq("commit", Boolean.TRUE)
                .in("business_id", opportunityUuids));
        return CollUtil.isEmpty(saleOrderInfos) ? Collections.emptyList() : saleOrderInfos;
    }

    private static void enableSaleOrde(SaleOrderInfo orderInfo) {
        orderInfo.setCommit(Boolean.TRUE);
        orderInfo.setStatus(SaleOrderStatusEnum.USER_CONFIRMED.getKey());
    }

    private static void disableSaleOrde(SaleOrderInfo orderInfo) {
        orderInfo.setCommit(Boolean.FALSE);
        orderInfo.setStatus(SaleOrderStatusEnum.ABANDONED.getKey());
    }

    /**
     * 设置相同商机下，其他订单为不启用状态，且订单状态为废单。
     * @param opportunityId 商机ID
     */
    private void disableSaleOrderForOpportunity(String opportunityId) throws Exception {
        this.baseMapper.disableSaleOrderForOpportunity(opportunityId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData changeSaleOrderStatus(ChangeSaleOrderStatusBO bo) throws Exception {
        SaleOrderInfo saleOrderInfo = this.baseMapper.selectById(bo.getId());
        saleOrderInfo.changeOrderStatus(bo.getStatus(), bo.getOperateUserId(), bo.getOperateDate());
        this.baseMapper.updateById(saleOrderInfo);
        return PageData.ok();
    }

    /**
     * 复制销售单
     * @param copySaleOrderInfoBo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData copySaleOrder(CopySaleOrderInfoBO copySaleOrderInfoBo) throws Exception {
        // 复制 sale_order_info
        SaleOrderInfo targetOrder = copySaleOrderInfo(copySaleOrderInfoBo);
        this.baseMapper.insert(targetOrder);
        log.info("copySaleOrder - orderInfo:{}", targetOrder);

        // 复制 sale_price_master
        CopySalePriceMasterBO copySalePriceMasterBo = new CopySalePriceMasterBO();
        BeanUtils.copyProperties(copySaleOrderInfoBo, copySalePriceMasterBo);
        copySalePriceMasterBo.setTargetSaleOrderId(targetOrder.getId());
        salePriceService.copySalePriceMaster(copySalePriceMasterBo);

        return PageData.ok("targetOrder", targetOrder);
    }

    @NotNull
    private SaleOrderInfo copySaleOrderInfo(CopySaleOrderInfoBO copySaleOrderInfoBo) throws Exception {
        SaleOrderInfo sourceOrder = this.baseMapper.selectById(copySaleOrderInfoBo.getSourceSaleOrderId());
        // 废弃其他订单
        disableSaleOrderForOpportunity(sourceOrder.getBusinessId());
        // 生成新订单
        SaleOrderInfo targetOrder = new SaleOrderInfo();
        BeanUtils.copyProperties(sourceOrder, targetOrder, "id");
        // 用户未自定义报价名称，系统默认生成
        if (!copySaleOrderInfoBo.hasName()) {
            targetOrder.setSaleOrderName("报价单-" + System.currentTimeMillis());
        } else {
            targetOrder.setSaleOrderName(copySaleOrderInfoBo.getTargetSaleOrderName());
        }

        initSaleOrder(targetOrder, copySaleOrderInfoBo.getOperateUserId(), copySaleOrderInfoBo.getOperateDate(), copySaleOrderInfoBo.getOperateUserCompanyId());
        return targetOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageData markSaleOrderDispatched(MarkSaleOrderDispatchedVO vo) throws Exception {
        if (SignSaleOrderStatusEnum._DISTRIBUTION.getKey() != vo.getSignStatus() && SignSaleOrderStatusEnum._CANCEL.getKey() != vo.getSignStatus()) {
            return PageData.error("请传入正确的标识类型!");
        }
        // 标记销售订单,被标记为已派单的不可删除
        SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
        saleOrderInfo.setId(vo.getSaleOrderId());
        saleOrderInfo.setDistributeStatus(vo.getSignStatus());
        saleOrderInfo.setGmtModified(vo.getOperateDate());
        saleOrderInfo.setGmtModifiedId(vo.getOperateUserId());
        boolean orderFlag = this.updateById(saleOrderInfo);

        // 标记系统单,被标记为已派单的不可删除
        Boolean priceMasterFlag = salePriceService.signPriceSheet(vo);
        if (orderFlag && priceMasterFlag) {
            return PageData.ok("订单添加派发标记成功!");
        }
        return PageData.error("订单添加派发标记失败!");
    }

    @Override
    public PageData getUnDispatchedSaleOrderPage(UnDispatchedSaleOrderPageBO bo) throws Exception {
        Page<SaleOrderInfoDTO> page = new Page<>(bo.getPageid(), bo.getPagesize()); // 准备分页参数
        List<SaleOrderInfoDTO> orderList = new ArrayList<>(); // 准备返回值

        // 按客户姓名组装查询条件
        List<String> customerIdList = new ArrayList<>();
        if (StrUtil.isNotBlank(bo.getCustomerName())) {
            // 按客户姓名模糊查询客户id
            QueryCustomerPageVo queryCustomerPageVo = new QueryCustomerPageVo();
            queryCustomerPageVo.setPageid(1);
            queryCustomerPageVo.setPagesize(99999);
            queryCustomerPageVo.setUserInfo(bo.getUserInfo());
            queryCustomerPageVo.setKeywords(bo.getCustomerName());
            // 分页获取客户信息
            Page<Customer> customerPage = crmCustomerService.customerPage(queryCustomerPageVo.convertToBo());
            log.debug("客户信息:" + JSON.toJSONString(customerPage));
            if (customerPage.getTotal() > 0) {
                customerIdList = customerPage.getRecords().stream().map(Customer::getUuid).collect(Collectors.toList());
            }
            // 如果查询得客户姓名不存在，直接返回空
            if (CollectionUtil.isEmpty(customerIdList)) {
                return PageData.ok(page, orderList);
            }
        }

        // 组装查询参数
        bo.setCustomerIdList(customerIdList);
        if (StrUtil.isNotBlank(bo.getXzqhdm())) {
            bo.setXzqhdm(XzqhUtils.getRegionCodePrefix(bo.getXzqhdm()));
        }
        // 查询销售订单分页
        orderList = this.baseMapper.getOrderPage(page, bo);
        // 设置返回字段
        setField(orderList);
        // 返回
        return PageData.ok(page, orderList);
    }

    @Override
    public SaleOrderInfo getSaleOrder(String opportunityUuid) {
        SaleOrderInfo saleOrderInfo = this.baseMapper.getSaleOrder(opportunityUuid);
        return saleOrderInfo;
    }

    @Override
    public SaleOrderInfoDTO getPriceMastersAndDetails(Long saleOrderId) throws Exception {
        SaleOrderInfo saleOrderInfo = this.getById(saleOrderId);
        SaleOrderInfoDTO saleOrderInfoDTO = new SaleOrderInfoDTO();
        BeanUtils.copyProperties(saleOrderInfo, saleOrderInfoDTO);
        Integer distributeStatus = ObjectUtil.isNotNull(saleOrderInfoDTO.getDistributeStatus()) && saleOrderInfoDTO.getDistributeStatus()
                .equals(1) ? saleOrderInfoDTO.getDistributeStatus() : 0;
        saleOrderInfoDTO.setDistributeStatus(distributeStatus);
        saleOrderInfoDTO.setPriceSheetList(salePriceService.getPriceMastersAndDetails(saleOrderId));
        return saleOrderInfoDTO;
    }

    @Override
    public SaleOrderInfoDTO getPriceMastersAndDetails(String opportunityId) throws Exception {
        SaleOrderInfo query = new SaleOrderInfo();
        query.setDeleted(false);
        query.setCommit(true);
        query.setBusinessId(opportunityId);
        SaleOrderInfo saleOrderInfo = this.baseMapper.selectOne(new QueryWrapper<>(query));
        SaleOrderInfoDTO saleOrderInfoDTO = new SaleOrderInfoDTO();
        BeanUtils.copyProperties(saleOrderInfo, saleOrderInfoDTO);
        saleOrderInfoDTO.setPriceSheetList(salePriceService.getPriceMastersAndDetails(saleOrderInfo.getId()));
        return saleOrderInfoDTO;
    }

    @Override
    public Page<SaleOrderInfoDTO> getPriceMastersAndDetails(SaleOrderPageBO bo) throws Exception {
        Page<SaleOrderInfo> page = new Page<>(bo.getPageid(), bo.getPagesize());
        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.getOrdersPage(page, bo);
        List<SaleOrderInfoDTO> saleOrderInfoDTOS = CopyUtils.copyList(saleOrderInfos, SaleOrderInfoDTO.class);
        for (SaleOrderInfoDTO saleOrderInfoDTO : saleOrderInfoDTOS) {
            saleOrderInfoDTO.setPriceSheetList(salePriceService.getPriceMastersAndDetails(saleOrderInfoDTO.getId()));
        }
        Page<SaleOrderInfoDTO> dtoPage = new Page<>(bo.getPageid(), bo.getPagesize());
        dtoPage.setTotal(page.getTotal());
        dtoPage.setRecords(saleOrderInfoDTOS);
        return dtoPage;
    }

    @Override
    public List<SaleOrderInfoDTO> getSaleOrderInfoListByCustomerId(List<String> customerIdList) {
        return this.baseMapper.getSaleOrderInfoListByCustomerId(customerIdList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByCustomerIds(List<String> deletedCustomerIds, Long operateUserId,
            Date operateDate) throws Exception {
        if (CollUtil.isEmpty(deletedCustomerIds)) {
            throw new MissBusinessParameterException("请传入要删除的客户ID");
        }
        this.baseMapper.deleteByCustomerIds(deletedCustomerIds, operateUserId, operateDate);
    }

    @Override
    public Integer getSystemNumberByOpportunityList(List<String> opportunities) {
        if (CollectionUtil.isEmpty(opportunities)) {
            return 0;
        }
        return this.baseMapper.getSystemNumberByOpportunityList(opportunities);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaleOrderInfo orderPaymentSuccess(SaleOrderBO saleOrderBO) throws Exception {
        if (ObjectUtil.isNull(saleOrderBO.getSaleOrderId())) {
            throw new IllegalBusinessException("销售订单ID不能为空");
        }
        SaleOrderInfo saleOrderInfo = this.getSaleOrderById(saleOrderBO.getSaleOrderId());
        saleOrderInfo.setStatus(saleOrderBO.getSaleOrderStatus().getKey());
        saleOrderInfo.setGmtModified(saleOrderBO.getOperateDate());
        saleOrderInfo.setGmtModifiedId(saleOrderBO.getOperateUserId());
        this.updateById(saleOrderInfo);
        return saleOrderInfo;
    }

    @Override
    public void cancelSaleOrder(CancelSaleOrderBO cancelSaleOrderBO) {
        List<Long> saleOrderIdList = cancelSaleOrderBO.getSaleOrderIdList();
        if (CollectionUtil.isEmpty(saleOrderIdList)) {
            throw new MissBusinessParameterException("saleOrderIdList must not empty");
        }

        // 恢复系统单的派单状态
        CancelPriceMasterBO cancelPriceMasterBO = new CancelPriceMasterBO();
        BeanUtils.copyProperties(cancelSaleOrderBO, cancelPriceMasterBO);
        cancelPriceMasterBO.setPriceMasterIdList(cancelSaleOrderBO.getPriceMasterIdList());
        salePriceService.cancelPriceMaster(cancelPriceMasterBO);

        // 筛选需要恢复的销售订单 - 全部系统单均没派单
        List<Long> notCancelSaleOrderIdList = salePriceService.getNotCancelSaleOrderIdList(cancelSaleOrderBO.getSaleOrderIdList());
        saleOrderIdList.removeIf(notCancelSaleOrderIdList::contains);
        if (CollectionUtil.isEmpty(saleOrderIdList)) {
            return;
        }

        // 恢复销售订单的派单状态
        QueryWrapper<SaleOrderInfo> wrapper = new QueryWrapper<>();
        wrapper.in("id", saleOrderIdList);
        wrapper.eq("deleted", false);

        SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
        saleOrderInfo.setDistributeStatus(SignSaleOrderStatusEnum._CANCEL.getKey());
        saleOrderInfo.setGmtModifiedId(cancelSaleOrderBO.getOperateUserId());
        saleOrderInfo.setGmtModified(cancelSaleOrderBO.getOperateDate());

        Integer rows = this.baseMapper.update(saleOrderInfo, wrapper);
        if (rows <= 0) {
            throw new IllegalBusinessException("修改销售订单派单状态失败");
        }
    }

    @Override
    public SaleOrderDetailDTO getSaleOrderDetail(QuerySaleOrderDetailBO queryBO) {
        if (StrUtil.isBlank(queryBO.getOpportunityUuid())) {
            throw new MissBusinessParameterException("opportunityUuid must not null");
        }
        if (StrUtil.isBlank(queryBO.getCustomerUuid())) {
            throw new MissBusinessParameterException("customerUuid must not null");
        }

        // 销售订单内容
        SaleOrderInfoDTO saleOrderInfoDTO = this.baseMapper.getSaleOrderDetail(queryBO);
        if (ObjectUtil.isNull(saleOrderInfoDTO)) {
            return new SaleOrderDetailDTO();
        }
        // 系统单列表
        QuerySalePriceMasterBO querySalePriceMasterBO = queryBO.copyOperateInfo(QuerySalePriceMasterBO.class);
        querySalePriceMasterBO.setSaleOrderId(saleOrderInfoDTO.getId());
        List<SalePriceMasterDTO> salePriceMasterList = salePriceService.getPriceMasterList(querySalePriceMasterBO);

        // 产品列表
        QuerySalePriceDetailBO querySalePriceDetailBO = queryBO.copyOperateInfo(QuerySalePriceDetailBO.class);
        querySalePriceDetailBO.setSaleOrderId(saleOrderInfoDTO.getId());
        List<SalePriceDetailDTO> salePriceDetailList =salePriceDetailService.getPriceDetailList(querySalePriceDetailBO);

        // 组装参数
        SaleOrderDetailDTO saleOrderDetailDTO = new SaleOrderDetailDTO();
        saleOrderDetailDTO.setSaleOrderInfoDTO(saleOrderInfoDTO);
        saleOrderDetailDTO.setSalePriceMasterDTOList(salePriceMasterList);
        saleOrderDetailDTO.setSalePriceDetailDTOList(salePriceDetailList);

        // 后置处理
        postHandle(saleOrderDetailDTO);

        return saleOrderDetailDTO;
    }

    /**
     * 批量确认销售订单
     * 直接改成支付完成,不校验【用户是否确认状态】
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String batchSaleOrderPaymentSuccess(BatchSaleOrderPaymentSuccessBO bo) {
        if (CollectionUtil.isEmpty(bo.getSaleOrderIdList())) {
            throw new MissBusinessParameterException("saleOrderIdList must not empty");
        }

        Integer successCount = 0;
        Integer failCount = 0;
        for (Long saleOrderId : bo.getSaleOrderIdList()) {
            SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
            saleOrderInfo.setId(saleOrderId);
            saleOrderInfo.setStatus(SaleOrderStatusEnum.PAID_SUCCESS.getKey());
            saleOrderInfo.setGmtModified(bo.getOperateDate());
            saleOrderInfo.setGmtModifiedId(bo.getOperateUserId());
            Integer rows = this.baseMapper.updateById(saleOrderInfo);
            if (rows <= 0) {
                failCount++;
                continue;
            }
            successCount++;
        }
        return String.format("批量确认销售订单完成,共%s条，成功%s条,失败%s条", bo.getSaleOrderIdList().size(), successCount, failCount);
    }

    @Override
    public Boolean queryHaveWorkOrder(QueryHaveWorkOrderBO queryBO) {
        if (ObjectUtil.isNull(queryBO)
                || StrUtil.isBlank(queryBO.getOpportunityUuid())
                || StrUtil.isBlank(queryBO.getCompanyId())) {
            log.error("参数不全,不做处理!");
            return Boolean.FALSE;
        }

        QueryWrapper<SaleOrderInfo> saleOrderInfoWrapper = new QueryWrapper<>();
        saleOrderInfoWrapper.select("id");
        saleOrderInfoWrapper.eq("business_id", queryBO.getOpportunityUuid());
        saleOrderInfoWrapper.eq("company_id", queryBO.getCompanyId());
        saleOrderInfoWrapper.eq("deleted", false);
        saleOrderInfoWrapper.eq("distribute_status", Integer.valueOf(SaleOrderDistributeStatusEnum.DISTRIBUTE.getKey()));

        List<SaleOrderInfo> saleOrderInfos = this.baseMapper.selectList(saleOrderInfoWrapper);
        Set<Long> saleOrderIdSet = saleOrderInfos.stream().map(SaleOrderInfo::getId).collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(saleOrderIdSet)) {
            log.info("没有任何已派单的销售订单");
            return Boolean.FALSE;
        }

        Integer count = salePriceService.queryHaveWorkOrder(saleOrderIdSet);
        if (count > 0) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    // 处理销售订单详情
    private void postHandle(SaleOrderDetailDTO saleOrderDetailDTO) {

    }

    // 设置返回字段
    private void setField(List<SaleOrderInfoDTO> orderList) {
        if (CollectionUtil.isEmpty(orderList)) {
            return;
        }
        for (SaleOrderInfoDTO orderInfo : orderList) {

            String customerName = "";
            // 查询客户姓名
            if (StrUtil.isNotEmpty(orderInfo.getCustomerId())) {
                CustomerDTO customer = crmCustomerService.getCustomerById(orderInfo.getCustomerId());
                customerName = ObjectUtil.isNull(customer) ? "" : String.valueOf(customer.getCustomerName());
            }
            // 查询创建人姓名
            TUser userDetail = systemUserService.getUserInfoByUserId(String.valueOf(orderInfo.getGmtCreateId()));
            String gmtCreateName = StrUtil.EMPTY;
            if (ObjectUtil.isNotNull(userDetail)) {
                gmtCreateName = userDetail.getNickName();
            }
            // 查询订单状态名称
            String statusName = tParamService.getNameByParamTypeAndValue("302", String.valueOf(orderInfo.getStatus()));
            // 查询支付方式名称
            String payModelName = tParamService.getNameByParamTypeAndValue("306", String.valueOf(orderInfo.getPayModel()));
            if (ObjectUtil.isNull(orderInfo.getOrderType())) {
                log.info("{}", orderInfo);
            }
            // 查询订单类型名称
            String orderTypeName = tParamService.getNameByParamTypeAndValue("303", String.valueOf(orderInfo.getOrderType()));

            // 返回
            orderInfo.setCustomerName(customerName);
            orderInfo.setGmtCreateName(gmtCreateName);
            orderInfo.setStatusName(statusName);
            orderInfo.setPayModelName(payModelName);
            orderInfo.setOrderTypeName(orderTypeName);
            orderInfo.setCommitName(orderInfo.getCommit() ? "销售单" : "报价单");
        }
    }


}
